<?php
class User_usuarios extends MY_Controller {

	var $ruta_fotos = './img/';

	public function __construct()
    {
    	# Al constructor le envío la clase Controlador, y el nombre de la entidad gestionada
    	parent::__construct(get_class($this), 'User_usuario');

    	$this->title = 'Usuarios :: Usuarios';
		$this->CARPETA_VISTAS = 'usuarios/';
		$this->nombre_entidad = 'Usuario';

		$this->pagina_ver = $this->CARPETA_VISTAS . 'usuario_ver_todos_view';
		$this->pagina_editar = $this->CARPETA_VISTAS . 'usuario_edit_view';
		$this->pagina_filtros_ver = $this->CARPETA_VISTAS . 'usuario_filtros_ver_todos_view';
	}

	/* IMPORTANTE: DEBE existir esta función. 
	 * Devuelve un arreglo que contiene el objeto de la entidad correspondiente, poblado con la información obtenida a 
	 * partir del formulario recibido a través de POST, y los objetos de otro tipo asociados al mismo.	*/
	protected function getObjetoDesdeForm()
	{
		// Se obtienen los datos del formulario para poblar el modelo
		$id_usuario = is_numeric($this->input->post('txt_id')) ? $this->input->post('txt_id') : NULL;
		$obj_usuario = $this->getObjeto($id_usuario);

		if(!$obj_usuario->exists()) {
			# Usuario nuevo
			$obj_usuario->nombre_usuario = $this->input->post('txt_nombre_usuario');
			$obj_usuario->nombre = $this->input->post('txt_nombre');
			
			$fecha_actual = date($this->formatoFechaGuardar);
			$obj_usuario->fecha_alta = $fecha_actual;
			
			// Si el usuario es nuevo, guardo la clave ingresada.
			$obj_usuario->clave = $this->input->post('txt_clave');
			$obj_usuario->confirm_password = $this->input->post('txt_clave_confirmar');
			$obj_usuario->baja = FALSE;
		}
		else {
			// Si es un usuario existente, la edición puede realizarse de distintas maneras
			$opcion = is_numeric($this->input->post('txt_opcion')) ? $this->input->post('txt_opcion') : '1';
			switch ($opcion) {
				case 2:
					# Cambiar clave
					$obj_usuario->clave = $this->input->post('txt_clave');
					$obj_usuario->confirm_password = $this->input->post('txt_clave_confirmar');
					break;

				case 3:
					# Cambiar foto
					break;
				
				default:
					# Edición estándar
					$obj_usuario->nombre_usuario = $this->input->post('txt_nombre_usuario');
					$obj_usuario->nombre = $this->input->post('txt_nombre');
					break;
			}
		}

		$obj_usuario->editable = TRUE;

		$datos['objEntidad'] = $obj_usuario;

		// Defino el objeto que se desea asociar y los asigno al arreglo. Si no hubiese, corresponde un arreglo vacío
		$id_rol = is_numeric($this->input->post('sel_rol')) ? $this->input->post('sel_rol') : NULL;
		$datos['objRelacionados'] = array(new User_rol($id_rol));

		return $datos;
	}


	/* IMPORTANTE: DEBE existir esta función. 
	 * Carga en el arreglo que luego se pasarán a las vistas, los datos correspondientes a otras entidades que se
	 * necesiten. Por ejemplo, en este método deben cargarse las entidades a las que puede asociarse o relacionarse
	 * la entidad actual. Si no se requiriesen, no se agrega nada. */
	protected function cargarDatosRelacionados($dataView)
	{
		// Creo un objeto del modelo, para poder buscar todos los datos en la BD
		$obj_rol = new User_rol();
		$dataView['listado_roles'] = $obj_rol->get_iterated();
		
		return $dataView;
	}

	/* IMPORTANTE: DEBE existir esta función. 
	 * Obtiene el listado de elementos de acuerdo a los filtros que se hayan establecido y enviado a través
	 * del método POST. Devuelve un detalle de los filtros aplicados (o vacío si no hubiera filtros)	*/	
	protected function _aplicarFiltros($dataView = array())
	{
		// Creo un objeto del modelo, para poblarlo con los datos que necesito mostrar
		$objEntidad = $this->getObjeto();
		$detalle_filtros = '';

		$nombre = trim($this->input->post('f_txt_nombre'));
		if(!empty($nombre)) { 
			$objEntidad->like('nombre_usuario', $nombre); 
			$detalle_filtros .= (!empty($detalle_filtros) ? ' | ' : '') . 'Nombre de usuario => ' . $nombre;
		}

		$opc_tipo_rol = is_numeric($this->input->post('f_opt_esadmin')) ? $this->input->post('f_opt_esadmin') : -1;
		if($opc_tipo_rol != -1) { 
			$objEntidad->where_related_user_rol('es_admin', $opc_tipo_rol); 
			$detalle_filtros .= (!empty($detalle_filtros) ? ' | ' : '') . 
								($opc_tipo_rol == 1 ? 'Sólo Usuarios Administradores' : 'Sólo Usuarios No Administradores');
		}

		$dataView['objEntidad'] = $objEntidad;
		$dataView['detalle_filtros'] = $detalle_filtros;

		return $dataView;
	}

	public function editar($id_elemento = NULL, $opcion = 1)
	{
		$dataView = array();
		$objEntidad = $this->getObjeto($id_elemento);
		$edicionStandard = TRUE;
		switch ($opcion) {
			case 1:
				# Opción por defecto. Es la edición común
				break;

			case 2:
				# Cambiar clave
				$dataView['title'] = 'Cambiar clave';
				$dataView['metodo_guardar'] = 'actualizar_clave';
				$dataView['pagina_editar'] =  $this->CARPETA_VISTAS . 'usuario_clave_edit_view';
				break;

			case 3:
				# Cambiar clave
				$dataView['title'] = 'Cambiar Foto de Perfil';
				$dataView['metodo_guardar'] = 'actualizar_foto';
				$dataView['pagina_editar'] =  $this->CARPETA_VISTAS . 'usuario_foto_edit_view';
				$controlador = strtolower($this->nombre_controlador);
				$dataView['nombre_controlador'] = $controlador;
				$dataView['id_usuario'] = $id_elemento;
				$dataView['metodo_subir_archivo'] = "cargarFotoPerfil(this.form.id, '$controlador')";
				$edicionStandard = FALSE;
				break;
			
			default:
				break;
		}
		$dataView['objEntidad'] = $objEntidad;
		
		if($edicionStandard) parent::_cargarFormEdicion($dataView);
		else parent::_loadFileUploadView($dataView, FALSE);
	}

	public function validarForm($datos = array())
	{	
		if($datos == array()) $datos = $this->getObjetoDesdeForm();
		$objEntidad = $datos['objEntidad'];
		$objRelacionados = $datos['objRelacionados'];
		$objEntidad->validate($objRelacionados);

		# Agrego las validaciones personalizadas para la carga de usuarios (Campos requeridos según tipo de edición)
		$campos_requeridos = array();
		if ($objEntidad->exists()) {
			$opcion = is_numeric($this->input->post('txt_opcion')) ? $this->input->post('txt_opcion') : '1';
			switch ($opcion) {
				case '2':
					$clave_ant_ingresada = $this->input->post('txt_clave_actual');
					# cambiar clave...
					if(empty($clave_ant_ingresada)) $campos_requeridos[] = 'Clave actual';
					else {
						$clave_ant_ingresada = $objEntidad->getCadenaEncriptada($clave_ant_ingresada);
						$objEntidadOriginal = $this->getObjeto($objEntidad->id);
						if($clave_ant_ingresada != $objEntidadOriginal->clave) $campos_requeridos[] = 'Incorrecta';
					}
					if(empty($objEntidad->clave)) $campos_requeridos[] = 'Clave';
					if(empty($objEntidad->confirm_password)) $campos_requeridos[] = 'Confirmar clave';
					break;

				case '3':
					# cambiar foto...
					break;
				
				default:
					# Edición estándar
					if(empty($objEntidad->nombre)) $campos_requeridos[] = 'Nombre';
					if(empty($objEntidad->nombre_usuario)) $campos_requeridos[] = 'Usuario';
					break;
			}
		}
		else {
			# El usuario es nuevo
			if(empty($objEntidad->nombre)) $campos_requeridos[] = 'Nombre';
			if(empty($objEntidad->nombre_usuario)) $campos_requeridos[] = 'Usuario';
			if(empty($objEntidad->clave)) $campos_requeridos[] = 'Clave';
			if(empty($objEntidad->confirm_password)) $campos_requeridos[] = 'Confirmar clave';
		}

		foreach ($campos_requeridos as $campo) {
			if ($campo == 'Incorrecta') $objEntidad->error->string .= "<i class='fa fa-ban'></i> La clave actual ingresada es incorrecta.</br>";
			else $objEntidad->error->string .= "<i class='fa fa-times'></i> El campo $campo es obligatorio.</br>";
		}

		if($this->input->is_ajax_request()) echo $objEntidad->error->string;
		else return $objEntidad->error->string;
	}

	public function actualizar_clave()
	{
		$datos = $this->getObjetoDesdeForm();
		$errorValidacion = $this->validarForm($datos);
		if(empty($errorValidacion))
		{
			# No hubo errores, actualizo la clave
			$id_usuario = $_SESSION[$this->template->getIdUserSessionName()];
			$objEntidad = $this->getObjeto($id_usuario);
			$clave_nueva = $objEntidad->getCadenaEncriptada(trim($this->input->post('txt_clave')));
			$objEntidad->where('id', $id_usuario)->update('clave', $clave_nueva);
			#$this->ver_perfil($dataView);
		}
		else
		{
			# Falló la validación de datos de acuerdo a las reglas de los modelos
			$dataView['error'] = 'Error: ' . $errorValidacion;
		}

		#$dataView['cargaCompleta'] = FALSE;
		$this->ver_perfil($dataView);
	}


	public function actualizar_foto()
	{
		// Intento guardar el archivo si hubiera
		$config['upload_path'] = $this->ruta_fotos;
		$config['allowed_types'] = 'jpg|jpge|png';
		
		$this->load->library('upload', $config);
		if (!$this->upload->do_upload()) {
			echo 'Error: ' . $this->upload->display_errors();
		}
		else {
			$datos_archivo = $this->upload->data();
			
			$id_usuario = $_SESSION[$this->template->getIdUserSessionName()];
			$objEntidad = $this->getObjeto($id_usuario);

			$path_foto_perfil = $this->ruta_fotos . $objEntidad->foto_perfil;
			// Si existiera foto previa, la elimino antes de guardar la nueva
			if (file_exists($path_foto_perfil)){
				unlink($path_foto_perfil);
			}

			$path_foto_min = $this->ruta_fotos . $objEntidad->getFotoPerfilMin();
			if (file_exists($path_foto_min)) {
				unlink($path_foto_min);
			}

			$objEntidad->where('id', $id_usuario)->update('foto_perfil', $datos_archivo['file_name']);
			$this->_redimensionar($datos_archivo['full_path']);

			$_SESSION[$this->template->getImgSessionName()] = $objEntidad->getFotoPerfilMin($datos_archivo['file_name']); #$this->_nombre_img_min($datos_archivo['file_name']);

			$dataView['cargaCompleta'] = FALSE;
			$this->ver_perfil($dataView);
		}
	}

	private function _redimensionar($nombre_img)
	{
		$config['image_library'] = 'gd2';
		$config['source_image'] = $nombre_img;
		$config['create_thumb'] = $miniatura;
		$config['thumb_marker'] = '_min';
		$config['width'] = 128;
		$config['height'] = 128;
		$config['maintain_ratio'] = TRUE;
		$this->load->library('image_lib', $config);
		$exito = $this->image_lib->resize();
		return $this->image_lib->display_errors();
	}

	public function ver_perfil($dataView = array()){
		$id_usuario = $_SESSION[$this->template->getIdUserSessionName()];
		$dataView['objUser'] = $this->getObjeto($id_usuario);
		$dataView['pagina_ver'] =  $this->CARPETA_VISTAS . 'usuario_ver_view';;
		$dataView['title'] = 'Perfil del usuario';
		$dataView['permitir_agregar_nuevo'] =  FALSE;
		$dataView['sin_filtros'] = TRUE;
		$dataView['metodo_filtrar'] = '';

		parent::ver_todos($dataView);
	}

	/* IMPORTANTE: DEBE existir esta función.
	 * Valida las condiciones que deben cumplirse para que un elemento pueda ELIMINARSE. */
	protected function validarEliminacion($id_elemento)
	{
		// No se permite la eliminación de usuarios
		return FALSE;
	}

	/* IMPORTANTE: DEBE existir esta función.
	 * Valida las condiciones que deben cumplirse para que un elemento pueda EDITARSE. */
	protected function validarEdicion($id_elemento)
	{
		$obj_usuario = $this->getObjeto($id_elemento);

		if($obj_usuario->exists()) {
			# El usuario existe. Se está queriendo editar su información
			if(!$obj_usuario->baja) {
				# El usuario no está dado de baja
				$id_usuario_logueado = $_SESSION[$this->template->getIdUserSessionName()];
				if ($id_usuario_logueado == $obj_usuario->id) {
					# El usuario quiere modificar SUS datos
					if($obj_usuario->editable) return TRUE; # Usuario editable
					else return FALSE;
				}
				else return FALSE; # No se puede editar datos de otros usuarios
			}
			else return FALSE; # No se modifican los usuarios inactivos
		}
		else return TRUE; # Se permite agregar usuarios nuevos
	}

	/* Carga todos los registros de un modelo o entidad (de acuerdo a los filtros o los últimos agregados) */
	public function ver_todos($dataView = array())
	{
		if ($this->template->currentUserIsAdmin($_SESSION[$this->template->getRolSessionName()])) {
			$dataView['metodo_cambio_estado'] = 'cambiar_estado';
			parent::ver_todos($dataView);
		}
		else $this->ver_perfil();
	}


	public function cambiar_estado($id_elemento)
	{
		$dataView['title'] = 'Cambiar estado de ' . $this->nombre_entidad;

		if(isset($_SESSION[$this->template->getIdUserSessionName()])) {
			$id_usuario_actual = $_SESSION[$this->template->getIdUserSessionName()];

			if($id_usuario_actual != $id_elemento) {
				// Se obtiene el objeto que se desea eliminar
				$obj_usuario = $this->getObjeto($id_elemento);

				// Valido si el usuario es editable antes de continuar
				if($obj_usuario->editable) {
					if(!$obj_usuario->baja) {
						$obj_usuario->baja = TRUE;
						$obj_usuario->fecha_baja = date($this->formatoFechaGuardar);
					}
					else $obj_usuario->baja = FALSE;

					// Se manejan transacciones para interactuar con la BD
					$obj_usuario->trans_begin();
					$obj_usuario->save();
					if ($obj_usuario->trans_status() === FALSE) // Se chequea el estado de la transacción
					{
					    $obj_usuario->trans_rollback(); // Si la transacción falló, hago un rollback
					}
					else
					{
					    $obj_usuario->trans_commit(); // Transacción exitosa, realizo el commit
					}

					$dataView['error'] = $obj_usuario->error->string; // Almaceno todos los errores que hubieran podido ocurrir					
				}
				else $dataView['error'] = 'El usuario ' . $obj_usuario->nombre_usuario . ' no puede editarse.';
			}
			else $dataView['error'] = 'Un usuario no puede cambiar su propio estado.';
		}
		else $dataView['error'] = 'No se ha iniciado sesión.';

		$this->ver_todos($dataView);
	}

	public function prueba()
	{
		// 1. Si el atributo pertenece directamente a la entidad, le envío el valor vacío.
		// 2 .Si el atributo pertenece a una entidad relacionada a la entidad actual, envío un arreglo con las mismas. Por ejemplo, si
		// se desea el atributo nombre de la tarea que pertenece al rol de un usuario, sería:
		// 'nombre' => array('user_tarea', 'user_rol'),
		// 3. Si envío como clave la palabra "bool", es porque debo mostrar Sí o No en lugar de True o False o 1 o 0.
		$dataView['datos_campos'] = array('nombre_usuario' => '',
										  'nombre' => array('user_rol'),
										  'fecha_alta'  => '', 
										  'baja'  => 'bool');
		$dataView['headers_datos'] = array('Usuario', 'Rol', 'Alta', 'De baja');

		parent::generar_excel($dataView);
	}
}